package org.amse.korovkin.ciphering.model.cipher.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 *
 * @author Mikhail Korovkin
 */
public class MathUtil {
    private static HashMap<Integer, Integer> pairs = null;
    private static final int MODULE = 257;

    private MathUtil() {
    }

    public static List<Integer> shiftRight(List<Integer> list) {
        int last = list.remove(list.size()-1);
        list.add(0, last);
        return list;
    }

    public static List<Integer> shiftLeft(List<Integer> list) {
        int first = list.remove(0);
        list.add(first);
        return list;
    }
    public static int getInverse(int a, int N) {
        int x = modul(a,N);
//        try {
            if (N == MODULE && pairs == null) {
                initPairs();
            }
            if (N == MODULE) {
                return pairs.get(x);
            } else return modul(gcd_enhanced(x, N), N);
//        } catch (NullPointerException ex) {
//            ex.printStackTrace();
//            System.out.println(ex.getMessage() + "    " + x);
//        }
//        throw new IllegalArgumentException("Can not find inverse element to: "+a);
    }

    public static int modul(int a, int N) {
        if (a < 0) {
            while (a<0) {
                a+=N;
            }
        } else {
            a = a % N;
        }
        return a;
    }
    
    public static List<Integer> modArray(List<Integer> array, int n) {
        List<Integer> result = new ArrayList<Integer>();
        for (Integer a : array) {
            result.add(modul(a,n));
        }
        return result;
    }

    public static int getPosByte(byte b) {
        if (b < 0) {
            return (256 + b);
        } else return b;
    }

    public static byte getSignedByte(int a) {
        if (a >=0 && a < 128) {
            return (byte)a;
        } else {
            if (a >= 128 && a <= 255) {
                return (byte) (a - 256);
            } else {
                throw new IllegalArgumentException("Wrong value of integet to" +
                        "do byte from it: "+ a );
            }
        }
    }

    private static void initPairs() {
        pairs = new HashMap<Integer, Integer>();
        for (int i = 1; i < MODULE; i++) {
            pairs.put(i, modul(gcd_enhanced(i, MODULE), MODULE));
        }
    }

    private static int gcd_enhanced(int a, int N) {
        int temp = 0;
        int q = 1;
        int s0 = 1;
        int s1 = 0;
        int t0 = 0;
        int t1 = 1;
        while (a != 0) {
            if (N % a == 0) {
                break;
            }
            q = N / a;
            temp = s1;
            s1 = s0 - q * s1;
            s0 = temp;
            temp = t1;
            t1 = t0 - q * t1;
            t0 = temp;
            temp = N % a;
            N = a;
            a = temp;
        }
        return t1;
    }
}
